﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
using GongSolutions.Wpf.DragDrop;
using System.Windows;

namespace TfsBacklogMgr.Main
{
    [NotifyPropertyChanged]
    public class Context : ViewModelBase, IDropTarget
    {
        #region Factory

        protected static Context _cache = new Context();
        protected static string _filename = "";

        public static Context GetContext()
        {
            return _cache;
        }

        internal static void LoadFrom(string fname)
        {
            _filename = fname;
        }

        public static void Load()
        {
            Context ctx = Context.GetContext();
            ctx.AddWorkItemTypes();
            ctx.AddIterations();
            ctx.AddUsers();
        }

        #endregion

        private ObservableCollection<Iteration> _iterations;
        private ObservableCollection<Iteration> _nonLeafIterations;
        private ObservableCollection<Iteration> _backlogIterations;
        private Iteration _currentSprintIter; // selects the top of the sprint hierarchy
        private Iteration _currentBacklogIter; // selects the top of the backlog hierarchy
        private ObservableCollection<User> _users;
        private ObservableCollection<User> _chosenUsers;
        private User _currentUser;
        private int _maxPoints;
        private int _maxHours;
        private string _tfsServer;
        private string _tfsProject;

        public Context()
        {
            _iterations = new ObservableCollection<Iteration>();
            _nonLeafIterations = new ObservableCollection<Iteration>();
            _backlogIterations = new ObservableCollection<Iteration>();
            _users = new ObservableCollection<User>();
            _chosenUsers = new ObservableCollection<User>();
        }

        internal void AddWorkItemTypes()
        {
            IFactory fac = Factory.GetFactory();

            WIT_Bug = fac.WITBug;
            WIT_Story = fac.WITStory;
            WIT_Task = fac.WITTask;

            WITF_Points = fac.WITFPoints;
            WITF_Hours = fac.WITFHours;
            WITF_Remain = fac.WITFRemain;

            WITF_Hours_Precision = fac.HoursPrecision;
            WITF_Points_Precision = fac.PointsPrecision;
            WITF_Remain_Precision = fac.RemainPrecision;

            // tickle user interface so that controls enable
            OnPropertyChanged("TfsIsConnected");
        }

        internal void AddIterations()
        {
            _iterations.Clear();
            _nonLeafIterations.Clear();
            _backlogIterations.Clear();

            foreach (var i in Iteration.GetAllIterations())
                _iterations.Add(i);
            AddSprintParentIterations();

            // add each top level backlog iteration to the list
            var root = Iteration.GetIteration("$");

            // add fake root iter to the top of the backlog so that root is selectable as a backlog container
            var backlogroot = Iteration.GetBacklogRoot();
            AddTopLevelBacklogIterations(backlogroot);

            if( _nonLeafIterations.Count > 0 )
                CurrentSprintIteration = _nonLeafIterations[0];
            if (_backlogIterations.Count > 0)
                CurrentBacklogIteration = _backlogIterations[0];
        }

        internal void AddUsers()
        {
            _users.Clear();
            _chosenUsers.Clear();
            foreach (var u in User.GetUsers())
            {
                _users.Add(u);
                if (u.IsChosen)
                    _chosenUsers.Add(u);
            }
            // if no users chosen, then choose all of them
            if (_chosenUsers.Count == 0)
            {
                foreach (var u in User.GetUsers())
                {
                    u.IsChosen = true;
                    _chosenUsers.Add(u);
                }
            }
        }

        internal void UpdateUsers()
        {
            foreach (var u in User.GetUsers())
            {
                if (u.IsChosen && ! _chosenUsers.Contains( u) )
                    _chosenUsers.Add(u);
                if (! u.IsChosen && _chosenUsers.Contains(u))
                    _chosenUsers.Remove(u);
            }
        }

        private void AddSprintParentIterations()
        {
            foreach (var i in Iteration.GetNonLeafIterations())
            {
                if (!i.IsPureBacklogIteration)
                    _nonLeafIterations.Add(i);
            }
        }

        private void AddTopLevelBacklogIterations(Iteration root)
        {
            if (root != null)
            {
                if (root.IsBacklogIteration)
                {
                    //if( ! _backlogIterations.Contains( root.Parent ) )
                    //    _backlogIterations.Add(root.Parent);
                    _backlogIterations.Add(root);
                }
                else
                    foreach (var i in root.SubIterations)
                        AddTopLevelBacklogIterations(i);
            }
        }

        public ObservableCollection<Iteration> AllIterations
        {
            get { return _iterations; }
        }

        /// <summary>
        /// Possible sprints - i.e. not including pure backlog iterations
        /// </summary>
        public ObservableCollection<Iteration> NonLeafIterations
        {
            get { return _nonLeafIterations; }
        }

        /// <summary>
        /// Current sprint
        /// </summary>
        public Iteration CurrentSprintIteration
        {
            get { return _currentSprintIter; }
            set { _currentSprintIter = value; }
        }

        public ObservableCollection<Iteration> BacklogIterations
        {
            get { return _backlogIterations; }
        }

        /// <summary>
        /// Current backlog iter
        /// </summary>
        public Iteration CurrentBacklogIteration
        {
            get { return _currentBacklogIter; }
            set { _currentBacklogIter = value; }
        }

        public ObservableCollection<User> AllUsers
        {
            get { return _users; }
        }

        public ObservableCollection<User> ChosenUsers
        {
            get { return _chosenUsers; }
        }

        public User CurrentUser
        {
            get { return _currentUser; }
            set { _currentUser = value; }
        }

        public List<StateAndReason> GetNextStatesFor(string WIT, string curState)
        {
            var states = Factory.GetFactory().GetNextStatesFor(WIT, curState);
            return states;
        }

        /// <summary>
        /// Location that settings are saved and loaded from
        /// </summary>
        public String Filename
        {
            get { return _filename; }
            set { _filename =value; }
        }

        public int MaxPoints
        {
            get { return _maxPoints; }
            set { _maxPoints = value; }
        }
        public int MaxHours
        {
            get { return _maxHours; }
            set { _maxHours= value; }
        }
        public int MaxRemain
        {
            get { return _maxHours; }
            set { _maxHours = value; }
        }

        public String TfsServer
        {
            get { return _tfsServer; }
            set { _tfsServer = value; OnPropertyChanged("TfsPath"); }
        }
        public String TfsProject
        {
            get { return _tfsProject; }
            set { _tfsProject = value; OnPropertyChanged("TfsPath"); }
        }

        public string TfsPath
        {
            get { return _tfsServer + "/" + _tfsProject; }
        }
        public bool TfsIsConnected
        {
            get { return !string.IsNullOrEmpty(_tfsProject); }
        }

        public string WIT_Story { get; set; }
        public string WIT_Task { get; set; }
        public string WIT_Bug { get; set; }

        public string WITF_Points { get; set; }
        public string WITF_Hours { get; set; }
        public string WITF_Remain { get; set; }

        public int WITF_Points_Precision { get; set; }
        public int WITF_Hours_Precision { get; set; }
        public int WITF_Remain_Precision { get; set; }

        #region Drag+Drop

        public void DragOver(DropInfo dropInfo)
        {
            if (dropInfo.Data is WorkItem &&
                dropInfo.TargetItem is Iteration)
            {
                dropInfo.DropTargetAdorner = DropTargetAdorners.Highlight;
                dropInfo.Effects = DragDropEffects.Move;
            }
            if (dropInfo.Data is WorkItem &&
                dropInfo.TargetItem is User)
            {
                dropInfo.DropTargetAdorner = DropTargetAdorners.Highlight;
                dropInfo.Effects = DragDropEffects.Move;
            }
        }


        public void Drop(DropInfo dropInfo)
        {
            if (dropInfo.Data is WorkItem &&
                dropInfo.TargetItem is Iteration)
            {
                WorkItem wi = dropInfo.Data as WorkItem;
                Iteration srcIter = wi.Iteration;
                Iteration targIter = dropInfo.TargetItem as Iteration;
                wi.ChangeToIteration(targIter);  // move the item and all child items
                targIter.UpdateTotals();
                srcIter.UpdateTotals();
            }
            if (dropInfo.Data is WorkItem &&
                dropInfo.TargetItem is User)
            {
                WorkItem wi = dropInfo.Data as WorkItem;
                User targUser = dropInfo.TargetItem as User;
                wi.AssignedTo = targUser;
            }
        }

        #endregion
    }
}
